﻿using UnityEngine;
using System;
using System.Collections.Generic;

namespace BackgroundEngines {
    public class ModuleBackgroundEngine : PartModule {
		[KSPField(isPersistant=true)]
		public bool set = false;

		[KSPField(isPersistant = true)]
		public float setThrust;

		[KSPField(isPersistant = true)]
		public Quaternion setAttitude;

		[KSPField(isPersistant = true)]
		public AllEngineData engineData;

		public class AllEngineData : IConfigNode {
			public List<EngineData> engines = new List<EngineData>();

			public void Save(ConfigNode n) {
				foreach (EngineData d in engines) {
					ConfigNode e = new ConfigNode("ENGINE");
					d.Save(e);

					n.AddNode(e);
				}
			}

			public void Load(ConfigNode n) {
				foreach (ConfigNode en in n.GetNodes("ENGINE")) {
					EngineData e = new EngineData();
					e.Load(en);

					engines.Add(e);
				}
			}
		};

		public class EngineData : IConfigNode {
			public string thrustTransform = "";
			public float minThrust = 0;
			public float maxThrust = 0;

			public List<Propellant> propellant = new List<Propellant>();

			public EngineData() {
			}

			public EngineData(ModuleEngines m) {
				minThrust = m.minThrust;
				maxThrust = m.maxThrust;

				propellant = m.propellants;

				thrustTransform = m.thrustVectorTransformName;
			}

			public void Save(ConfigNode n) {
				n.AddValue("minThrust", minThrust);
				n.AddValue("maxThrust", maxThrust);
				n.AddValue("thrustTransform", thrustTransform);

				foreach (Propellant p in propellant) {
					ConfigNode pn = new ConfigNode("PROPELLANT");
					p.Save(pn);
					n.AddNode(pn);
				}
			}

			public void Load(ConfigNode n) {
				float.TryParse(n.GetValue("minThrust"), out minThrust);
				float.TryParse(n.GetValue("maxThrust"), out maxThrust);
				thrustTransform = n.GetValue("thrustTransform");

				foreach (ConfigNode pn in n.GetNodes("PROPELLANT")) {
					Propellant p = new Propellant();
					p.Load(pn);

					propellant.Add(p);
				}
			}
		}

		public void FixedUpdate() {
			if (part.isControllable && set && TimeWarp.CurrentRate > 1) {
				DoThrust(vessel, setThrust, setAttitude, engineData);
			}
		}

		public static void DoThrust(Vessel v, float thrust, Quaternion attitude, AllEngineData data) {
			double UT = v.orbit.StartUT;
			Vector3d newV = new Vector3d();

			foreach (EngineData d in data.engines) {
				float engineThrust = (d.maxThrust - d.minThrust) * thrust + d.minThrust;
				newV += TimeWarp.CurrentRate * v.orbit.getOrbitalVelocityAtUT(UT).normalized * engineThrust / v.GetTotalMass();
			}

			//Debug.Log("BE: " + v.orbit.StartUT + " UT " + UT + " gap: " + (UT - v.orbit.StartUT));
			//Debug.Log("BackgroundEngine: eccVec: " + v.orbit.eccVec + " pos: " + v.orbit.getRelativePositionAtUT(UT) + " vel: " + v.orbit.getOrbitalVelocityAtUT(UT));
			v.orbit.UpdateFromStateVectors(v.orbit.getRelativePositionAtUT(UT), v.orbit.getOrbitalVelocityAtUT(UT), v.orbit.referenceBody, UT );
			//Debug.Log("BackgroundEngine: eccVec: " + v.orbit.eccVec + " pos: " + v.orbit.getRelativePositionAtUT(UT) + " vel: " + v.orbit.getOrbitalVelocityAtUT(UT));
			
			// Don't know if this is strictly required
			v.protoVessel.orbitSnapShot = new OrbitSnapshot(v.orbit);
			
			//Debug.Log("BackgroundEngine: Doing thrust for vessel " + v.RevealName() + " with thrust " + thrust + " and attitude " + attitude);
		}

		public static void FixedBackgroundUpdate(Vessel v, uint id, Func<Vessel, float, string, float> resourceRequest) {
			foreach (ProtoPartSnapshot p in v.protoVessel.protoPartSnapshots) {
				if (p.flightID == id) {
					foreach (ProtoPartModuleSnapshot m in p.modules) {
						bool isSet;
						Boolean.TryParse(m.moduleValues.GetValue("set"), out isSet);

						if (isSet) {
							float thrust;
							float.TryParse(m.moduleValues.GetValue("setThrust"), out thrust);
							Quaternion attitude = KSPUtil.ParseQuaternion(m.moduleValues.GetValue("setAttitude").Trim('(', ')'));

							AllEngineData d = new AllEngineData();
							d.Load(m.moduleValues.GetNode("engineData"));

							DoThrust(v, thrust, attitude, d);
						}
					}
				}
			}
		}

		[KSPEvent(guiActive = true, guiName = "Set Thrust Parameters")]
		public void SetThrust() {
			set = true;
			SetEventActives();

			setThrust = vessel.ctrlState.mainThrottle;

			// Convert from AliceWorld
			Vector3d progradeVec = vessel.orbit.GetRelativeVel().normalized;
			progradeVec = new Vector3d(progradeVec.x, progradeVec.z, progradeVec.y);

			setAttitude = Quaternion.FromToRotation(progradeVec, vessel.GetFwdVector().normalized);

			engineData = new AllEngineData();
			foreach (ModuleEngines me in part.FindModulesImplementing<ModuleEngines>()) {
				engineData.engines.Add(new EngineData(me));
			}
		}

		[KSPEvent(guiActive = true, guiName = "Unset Thrust Parameters")]
		public void UnsetThrust() {
			set = false;
			SetEventActives();
		}

		public void SetEventActives() {
			if (set) {
				Events["SetThrust"].active = false;
				Events["UnsetThrust"].active = true;
			}
			else {
				Events["SetThrust"].active = true;
				Events["UnsetThrust"].active = false;
			}
		}

		public override void OnLoad(ConfigNode node) {
			SetEventActives();
		}
    }
}
